package sprint2;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.InputMismatchException;
import java.util.Scanner;

/**
 * @author Vincent van Andel
 * @author Fabian Mengerink
 *
 */
public class Character implements Serializable {

	private static Scanner in = new Scanner(System.in);
	private Scanner scanner = new Scanner(System.in);
	

	private Location current;
	private int currentLocation;
	private Inventory inventory = new Inventory(12);
	private ArrayList<Item> inventoryItems = new ArrayList<Item>();
	private double hpMax;
	private double hpNow;
	private double armour;
	private double power;
	private double hitrating;
	private double dodgerating;
	private int speed;
	private double critChance;
	private double critDamage;

	public Character(ArrayList<Location> locations, Location current,
			int currentLocation, Inventory inventory,
			ArrayList<Item> inventoryItems, double hpMax, double armour,
			double power, double hitrating, double dodgerating, int speed,
			double critChance, double critDamage) {
		//this.locations = locations;

		this.current = current;
		this.currentLocation = currentLocation;
		this.inventory = inventory;
		this.inventoryItems = inventoryItems;
		this.hpMax = hpMax;
		this.hpNow = hpMax;
		this.armour = armour;
		this.power = power;
		this.hitrating = hitrating;
		this.dodgerating = dodgerating;
		this.speed = speed;
		this.critChance = critChance;
		this.critDamage = critDamage;
		locations = Apl.boot.getLocations();
	}


	public Character(int currentLocation, double hpMax, double armour, double power, double hitrating, double dodgerating,
			int speed, double critChance, double critDamage) {
		this.currentLocation = currentLocation;
		this.hpMax = hpMax;
		this.hpNow = hpMax;
		this.armour = armour;
		this.power = power;
		this.hitrating = hitrating;
		this.dodgerating = dodgerating;
		this.speed = speed;
		this.critChance = critChance;
		this.critDamage = critDamage;
	
	}

	/**
	 * slaat het spel op!	
	 */

	public void save() throws FileNotFoundException, IOException {
		Apl.saven();
	}

	/**
	 * print alle connecties waar je naar toe kan, wacht op je invoer, en
	 * controleert of je invoer een geldige connectie is
	 * <p>
	 * <b>connectingLocations:</b> alle kamers waar je naar toe kan <br>
	 * <b>location:</b> Het object van de huidige kamer
	 * @throws ClassNotFoundException 
	 *
	 *
	 */

	public void chooseLocation(int nr) throws FileNotFoundException,
			IOException, ClassNotFoundException {
		int num = 0;
		ArrayList<Location> connectingLocations = new ArrayList<Location>();
		setCurrentLocation(nr);
		Location location = getLocation(nr);
		connectingLocations = Apl.boot.ArrayList(nr);

		System.out.println("Naar welke kamer wil je gaan:");
		if (location instanceof Teleport) {
			// checkt of de huidigde locatie een
			// teleporter is en dus misschien
			// een sleutel nodig heeft
			teleport(location, connectingLocations, num, nr);
		} else { // dan is het dus automatisch een kamer
			for (Location l : connectingLocations) { // print alle kamers waar
				// je naar toe kan
				System.out.println(l);
			}

			try {
				num = in.nextInt();
			} catch (InputMismatchException e) {
				System.out.println("Dit is geen geldige invoer ");
				in = new Scanner(System.in);
				chooseLocation(nr);
			}

			boolean con1 = (location.getCon1() == num);
			boolean con2 = (location.getCon2() == num);
			boolean con3 = (location.getCon3() == num);
			boolean con4 = (location.getCon4() == num);
			boolean con5 = (location.getCon5() == num);
			if (con1 || con2 || con3 || con4 || con5) {
				// controleert of je
				// naar de kamer toe kan
				// waar je naar toe wilt
				setCurrentLocation(num);
				// wijzigd de huidige locatie in de
				// gekozen locatie
			} else {
				System.out
						.println(" Geen geldige keuze, kies een kamer waar je wel naar toe kan");
				chooseLocation(nr);
				// roept de locatie wissel methode opnieuw
				// aan omdat je input geen connecterende
				// kamer was
			}
		}

	}

	/**
	 * methode werkt exact als <b>chooseLocation</b>: <br>
	 * print alle connecties waar je naar toe kan, wacht op je invoer, en
	 * controleert of je invoer een geldige connectie is
	 * <p>
	 * enige verschil is dat je als je geen sleutel hebt alleen terug kunt naar
	 * de locatie waar je vandaag kwam (con1)
	 *
	 * @param location
	 *            huidige locatie (object)
	 * @param connectingLocations
	 *            ArrayList met integers met nummers van conttecterende locaties
	 *            (geen index)
	 * @param num
	 *            nummer (niet index) waar je naar toe wil
	 * @param nr
	 *            nummer van de huidige locatie
	 * @throws FileNotFoundException
	 *
	 * @throws IOException
	 * @throws ClassNotFoundException 
	 */
	public void teleport(Location location,
			ArrayList<Location> connectingLocations, int num, int nr)
			throws FileNotFoundException, IOException, ClassNotFoundException {
		int teleportnr = ((Teleport) location).getKeynr();
		int keynr = 0;
		inventoryItems = inventory.getInventory();
		boolean keyInInventory = false;
		for (Item i : inventoryItems) { // zoekt sleutel in inventory
			if (i instanceof Key) {
				keynr = ((Key) i).getUniqueNumber();
				if (keynr == teleportnr)
					keyInInventory = true;
			}
		}
		if (keyInInventory) { // als je de sleutel hebt die bij de
			// teleporter hoort
			for (Location l : connectingLocations) { // print alle connecting
				// locations
				System.out.println(l);

			}
			try {

				num = in.nextInt();
			} catch (InputMismatchException e) {
				System.out.println("Dit is geen geldige invoer ");
				in = new Scanner(System.in);
				chooseLocation(nr);
			}
			System.out.println("De teleporter reageert op een sleutel en activeert!");
			boolean con1 = (location.getCon1() == num);
			boolean con2 = (location.getCon2() == num);
			boolean con3 = (location.getCon3() == num);
			boolean con4 = (location.getCon4() == num);
			boolean con5 = (location.getCon5() == num);
			if (con1 || con2 || con3 || con4 || con5) { // checkt of de invoer
				// een connecterende
				// kamer is
				in = new Scanner(System.in);
				setCurrentLocation(num);
			} else {
				in = new Scanner(System.in);
				System.out.println(" Geen geldige keuze");
				chooseLocation(nr); // roept opnieuw de keuze methode aan
			}
		} else { // als je niet de sleutel hebt voor deze teleporter
			System.out.println("Je hebt niet de benodigde sleutel");
			Location l = Apl.boot.getLocations().get(location.getCon1() - 1); // print
			// con1
			// (waar
			// je
			// vandaan
			// komt)
			System.out.println(l);
			num = in.nextInt();
			if (location.getCon1() == num) { // checkt of waar je wel naar toe
				// kunt, waar je naar toe wil
				setCurrentLocation(num); // verandert de huidige locatie in de
				// gekozen locatie
			} else {
				in = new Scanner(System.in);
				System.out.println(" Geen geldige keuze");
				chooseLocation(nr); // roept opnieuw de locatie wissel methode
				// aan
			}

		}

	}

	/**
	 *
	 * @param nr
	 * @return De Location met de nr meegegeven als argument
	 */
	private Location getLocation(int nr) { // Returned een kamer aan de hand van
		// zijn nummer
		ArrayList<Location> locations = Apl.boot.getLocations();
		for (Location l : locations) {
			if (l.getNr() == nr) { // zoekt de gewenste kamer op basis van zijn
				// nummer
				return l;
			}
		}
		return null;
	}
/**
 * 			Deze methode set de huidige locatie naar kamer die je hebt gekozen in chooseLocation
 * 			en drukt de bijbehorende tekstfile er van af
 * @param chosenLocation
 * 			Het nummer (niet index) van de kamer waar je naar toe wilt
 * @throws FileNotFoundException
 * @throws IOException
 * @throws ClassNotFoundException 
 */
	public void setCurrentLocation(int chosenLocation)
			throws FileNotFoundException, IOException, ClassNotFoundException {
		this.currentLocation = chosenLocation; // slaat de gekozen locatie op in
		current = getLocation(this.currentLocation); // laad het object van de
		// gekozen kamer
		if (current.getObject() == 0) { // als er geen object in de kamer af,
			// print de file van de kamer
			current.printOut(current.getFileName());
		} else {
			// als er een object in de kamer is print de huidige kamer met item,
			// 01 file is nodig ook al is er geen grafisch verschil
			String[] filename = (current.getFileName()).split(".txt");
			String strFilename = filename[0].toString() + "01.txt";
			current.printOut(strFilename);

		}

		check(); // kijkt of er op de huidige locatie een quest moet worden
		// gestart
		int monster = current.getMonster();
		if (monster > 0 && monster < 4) { // bedoeld om een kans te geven een
			// monster tegen het lijf te lopen
			// TODO: make randoms
		}
		if (monster > 3) { // roept een specifiek monster op
			Enemy enemy = null;
			ArrayList<Enemy> enemies = Apl.boot.getEnemies();
			for (int i = 0; i < enemies.size(); i++) {
				if (monster == (i + 3)) {
					enemy = enemies.get(i);
					if (!enemy.isBeaten()) { // word gecontroleerd of deze
						// vijand al verslagen is

						BattleSystem bs = new BattleSystem(enemy,
							Apl.boot.getCharacter());
						try {
							bs.simuleer(Apl.boot.getCharacter(),
									"alien.txt");
						} catch (ClassNotFoundException e) {
							e.printStackTrace();
						}
						if (hpNow != 0) { // als je eigen hp nog hoger is dan 0
							// heb je gewonnen
							enemy.setBeaten(true); // oftewel de tegenstander is
							// verslagen
						}
						Apl.boot.getCharacter().choice(); // vraagt wat
						// je nu wil
						// doen
					}
				}
			}
		}
	}

/**
 *  Deze methode vraagt zodra je de vorige actie hebt gedaan wat je nu wilt doen
 *
 * @throws FileNotFoundException
 * @throws IOException
 * @throws ClassNotFoundException 
 */

	public void choice() throws FileNotFoundException, IOException, ClassNotFoundException {
		in = new Scanner(System.in);
		int choice = 0;
		System.out.println("Wat wil je doen?");
		current = Apl.boot.getLocations().get(currentLocation - 1);
		if (current.getObject() != 0) {
			// als er geen obect is word deze regel niet afgedrukt
			System.out.println("1 = met een object ");
		}
		System.out.println("2 = naar een andere kamer gaan");
		System.out.println("3 = een item uit jouw inventory gebruiken");
		System.out.println("4 = saven");
		System.out.println("5 = saven & exit");
		try {
			choice = in.nextInt();
		} catch (InputMismatchException e) {
			System.out.println("Dit is geen geldige invoer ");
			in = new Scanner(System.in);
		}
		switch (choice) {
		case 1:
			if (current.getObject() > 0) { // controleerd of er een object
				// aanwezig is
				useObject();
			} else {
				System.out.println("Geen geldige keuze");
				choice();
			}
			break;
		case 2:
			chooseLocation(currentLocation);// roept een methode aan waarin word
			// gekeken waar je naar toe kan
			choice();
			break;
		case 3:
			useInventory();
			break;
		case 4:
			save(); // slaat alle huidige variabelen van character op
			choice();
			break;
		case 5:
			save();// slaat alle huidige variabelen op en sluit het spel af
			System.exit(0);
			break;
		default: // als de invoer niet geldig is word choice opnieuw aangeroepen
			System.out.println("Geen geldige keuze");
			choice();
			break;
		}
	}

	/**
	 * 	pak het item op dat in deze kamer ligt.
	 * @throws FileNotFoundException
	 * @throws IOException
	 * @throws ClassNotFoundException 
	 */

	private void useObject() throws FileNotFoundException, IOException, ClassNotFoundException {
		in = new Scanner(System.in);
		int choice = 0;
		System.out.println("In deze kamer ligt:");
		Item item = null;
		for (int i = 0; i < Apl.boot.getItems().size(); i++) { // print het
			// aanwezige
			// item
			if (current.getObject() == (i + 1)) {
				item = Apl.boot.getItems().get(i);
				System.out.println(item);
				if (item instanceof Creature) { // geeft een foutmelding als je
					// een dier probeert op te
					// pakken (moet je vangen)
					System.out
							.println("Je kunt hem niet oppakken. Gebruik een vangnet, om hem te vangen!");
					choice();
				}
				System.out.println("Wil je het oppakken? Toets dan 1 in, anders toets 0 in");
				try {
					choice = in.nextInt();
				} catch (InputMismatchException e) {
					System.out.println("Dit is geen geldige invoer ");
					in = new Scanner(System.in);
				}
				if (choice == 1) {
					in = new Scanner(System.in);
					if (!item.isOpgepakt()) {
						item.setOpgepakt(true); // zet de opgepakt variabele van
						// het item op true
						current.setObject(0); // verwijderd het item uit de
						// kamer
						inventory.addItem(item); // voegt item aan inventory toe
					}
				}
			}
		}
		in = new Scanner(System.in);
		choice();
	}

	/**
	 *	checked of er op deze locatie iets bijzonders is (zoals een quest starten)
	 * @throws FileNotFoundException
	 * @throws IOException
	 * @throws ClassNotFoundException 
	 */

	public void check() throws FileNotFoundException, IOException, ClassNotFoundException {
		switch (currentLocation) {
		case 1:
			printFile("introtext.txt");
			break;
		case 25: // roept de red de bijzondere levensvormen quests aan
			printFile("artichokeplanetquest.txt");
			break;
		case 27: // roept de bemiddel tussen 2 beschavingen quest aan
			SaveCiv s = new SaveCiv();
			break;
		case 28:
			printFile("gevechtsschip_quest.txt");
			break;
		case 71: 
			printFile("gaussometerintro.txt");
			Gaussometer gaussometer = new Gaussometer();
			gaussometer.gaussometerRun();
			break;
		case 85:
			printFile("ZwargatGevallen.txt");
			break;
		case 86:
			printFile("gaussoUitlegLS.txt");
			Gaussometer gaussometer1 = new Gaussometer();
			gaussometer1.gaussometerRun();
			scanner.next();
			printFile("EindeZwargat.txt");
			scanner.next();
			setCurrentLocation(14);
			break;
		case 87:
			printFile("ZwartgatUitleg1.txt");
			break;
		default: // als er geen quest op deze locatie is gebeurd er niets.
			break;
		}
	}
	/**
	 * Een item uit de inventory gebruiken
	 * @throws IOException
	 * @throws FileNotFoundException
	 * @author Marco Schultewolter
	 * @throws ClassNotFoundException 
	 */
	private void useInventory() throws FileNotFoundException, IOException, ClassNotFoundException {
		if (inventory.getInventory().size() == 0) {
			System.out.println("Jouw inventory is leeg...");
		} else {
			System.out.println("\nKies item.");
			inventory.printInventory(true);
			int itemKeuze = 0;
			do {
				try {
					itemKeuze = in.nextInt();
				} catch (InputMismatchException ime) {
					System.out.println("Geen geldige invoer.");
					choice();
				}
			} while (itemKeuze < 0
					|| itemKeuze >= inventory.getInventory().size());
			Item item = inventory.getInventory().get(itemKeuze);

			// CatchingNet
			if (item instanceof CatchingNet) {
				CatchingNet cn = (CatchingNet) item;
				if (current.getObject() != 0 && Apl.boot.getItems().get(current.getObject() - 1) instanceof Creature) {
					Creature currentObject = (Creature) Apl.boot.getItems()
							.get(current.getObject() - 1);
					if (currentObject instanceof BigCreature) {
						BigCreature bc = (BigCreature) currentObject;
						if (bc.isShrinked()) {
							if (!cn.useItem(currentObject, inventory)) {
								System.out
										.println("Jammer. Het wezen was te snel. Probeer het gewoon nog een keer...");
							} else {
								bc.setOpgepakt(true);
								current.setObject(0);
								System.out
										.println("Wohoo! Gevangen! Hij is nu in jouw inventory!");
							}
						} else {
							System.out
									.println("Het wezen is te groot voor jouw vangnet. Heb je een krimppistool? Dan kun je hem krimpen!");
						}
					} else {
						if (!cn.useItem(currentObject, inventory)) {
							System.out
									.println("Jammer. Het wezen was te snel. Probeer het gewoon nog een keer...");
						} else {
							currentObject.setOpgepakt(true);
							current.setObject(0);
							System.out
									.println("Wohoo! Gevangen! Hij is nu in jouw inventory!");
						}
					}
				} else {
					System.out
							.println("Hier is niks, dat je kunt vangen...");
				}
			}
			// ShrinkGun
			else if (item instanceof ShrinkGun) {
				if (current.getObject() != 0 && Apl.boot.getItems().get(current.getObject() - 1) instanceof BigCreature) {
					ShrinkGun sg = (ShrinkGun) item;
					if (Apl.boot.getItems().get(current.getObject() - 1) instanceof BigCreature) {
						BigCreature bc = (BigCreature) Apl.boot.getItems()
								.get(current.getObject() - 1);
						if (bc.isShrinked()) {
							System.out
									.println("Het wezen is al gekrompen!");
						} else {
							sg.useItem(bc);
							System.out
									.println("Bzzzzzt! Het wezen is gekrompen.");
						}
					}
				} else {
					System.out.println("Hier is niks om te krimpen!");
				}
			} 
			
			// Creature
			else if (item instanceof Creature
					&& Apl.boot.getLocations().get(currentLocation - 1) instanceof Arkschip) {
				Arkschip ark = (Arkschip) Apl.boot.getLocations().get(
						currentLocation - 1);
				ark.addCreature((Creature) item);
				System.out.println("Je hebt een " + item
						+ " op de arkschip geplaatst.");
				if (ark.isVol()) {
					System.out
							.println("Alle nodige dieren zijn verzameld. Dank u wel!");
				} else {
					System.out
							.println("Er zijn nog niet alle nodige dieren verzameld. Kunt u de rest nog zoeken?");
				}
				inventory.removeItem(itemKeuze);
			}

			// BattleShipControlPanel
			else if (item instanceof BattleShipControlPanel 
					&& Apl.boot.getLocations().get(currentLocation - 1) instanceof BattleShip) {
				BattleShip bsLocation = (BattleShip) Apl.boot.getLocations().get(currentLocation - 1);
				bsLocation.tryToAttack();
			}
			
			// Alle andere items
			else {
				item.useItem();
			}
		}

		choice();
	}

	/**
	 *  print de meegegeven file uit
	 * @param filename
	 * 			filename van de file die geprint moet worden
	 */

	public void printFile(String filename) { // drukt een file af
		BufferedReader in = null;
		try {
			File file = new File(filename);
			in = new BufferedReader(new FileReader(file));
		} catch (FileNotFoundException e) {
			System.out.println("The file doesn't exist.");
			System.exit(0);
		} catch (IOException e) {
			System.out.println("I/O Error");
			System.exit(0);
		}
		try {
			while (in.ready()) {
				System.out.println(in.readLine());
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

	public double getHpMax() {
		return this.hpMax;
	}

	public double getHpNow() {
		return this.hpNow;
	}

	public void setHpNow(double hpNow) {
		this.hpNow = hpNow;
	}

	public double getArmour() {
		return this.armour;
	}

	public double getPower() {
		return this.power;
	}

	public double getHitrating() {
		return this.hitrating;
	}

	public double getDodgerating() {
		return this.dodgerating;
	}

	public int getSpeed() {
		return this.speed;
	}

	public double getCritChance() {
		return this.critChance;
	}

	public double getCritDamage() {
		return this.critDamage;
	}
}
